#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>

#define QLEN		1
#define MAX_SIZE    	80
#define TIMEOUT		0.1

struct  sockaddr_in ladoServ, endServ; /* contem dados do servidor */
struct  sockaddr_in endCli; /*  estrutura do cliente    */
int     sd_serv, sd_cli, novo_sd;	/* socket descriptor */
int	tamanhoEstrutura;	/* tamanho da estrutura */
int     alen,n;          /* tamanho do endereco         */
int	pulsoRecebido=0; /* status da conexao */
char    bufout[MAX_SIZE]; /* buffer de dados enviados  */
char	bufin[MAX_SIZE];  /* buffer p receber dados */
char	porta[] = "2020"; /* porta para conexao */

pthread_t th1, th2; /* threads */

void sender();
void receiver();

int main(int argc,char * argv[])
{
	
	/* criando a thread sender */
	pthread_create(&th1, NULL, (void *) sender, NULL);
	/* criando a thead receiver */
	pthread_create(&th2, NULL, (void *) receiver, NULL);
	
	/* aguardando o termino das tarefas ... */
	pthread_join(th1, NULL); pthread_join(th2, NULL);
}

void receiver()
{
	printf("Receiver\n");
	clock_t timeout;	/* timeout do heartbeat */
	time_t rawtime;		/* inicializador de tempo */
	struct tm * timeinfo;	/* struct com info de data e hora */
		
	memset((char *)&endServ,0,sizeof(endServ)); /* limpa estrutura */
	
	/* Preenchendo as informacoes sobre o receiver */
	endServ.sin_family      = AF_INET; /* config. socket p. internet*/
	endServ.sin_addr.s_addr = inet_addr("127.0.0.1"); /* ip local */
	endServ.sin_port        = htons(atoi(porta)); 
	
	/* Cria socket UDP para receiver */
	sd_serv = socket(AF_INET, SOCK_DGRAM, 0);
	if (sd_serv < 0) {
		fprintf(stderr, "Falha ao criar socket!\n");
		exit(1); }
		
	/* liga socket a porta e ip */
	if (bind(sd_serv, (struct sockaddr *)&endServ, sizeof(endServ)) < 0) {
		fprintf(stderr,"Bind Falhou no Receiver!\n");
		exit(1); }
	
	/* Este servidor entra num loop infinito esperando um heartbeat */
	while(1) {
		/* inicia o buffer */
		memset(bufin,0x0,MAX_SIZE);
		tamanhoEstrutura = sizeof(endCli);
		/* recebe a mensagem  */
		timeout = clock () + TIMEOUT * CLOCKS_PER_SEC ;
		while(clock() < timeout)
		{
			n = recvfrom(sd_serv, bufin, MAX_SIZE, 0, (struct sockaddr *) &endCli, &tamanhoEstrutura);
			if(n > 0)
			{
				//Recebeu o pulso
				pulsoRecebido=1;
				break;
			}
			pulsoRecebido = 0; //se o timeout estourar, tem que estar desconectado
		}
		if(!pulsoRecebido)
			printf("Pulse Timed Out");
   
		/* imprime o heartbeat recebido */
		printf("%s\n",bufin);
    
	} /* fim do while */
}


//-------------------------------------------------------------------------------------------------------------


void sender()
{
	clock_t timeout;	/* timeout do heartbeat */
	time_t rawtime;		/* inicializador de tempo */
	struct tm * timeinfo;	/* struct com info de data e hora */
		
	memset((char *)&ladoServ,0,sizeof(ladoServ)); /* limpa estrutura */
	memset((char *)&bufout,0,sizeof(bufout)); /* limpa buffer */
	ladoServ.sin_family      = AF_INET; /* config. socket p. internet*/
	ladoServ.sin_addr.s_addr = inet_addr("127.0.0.1"); /* ip local */
	ladoServ.sin_port        = htons(atoi(porta));
	
	memset((char *)&endServ,0,sizeof(endServ)); /* limpa endCli */
	endCli.sin_family      = AF_INET; /* config. socket p. internet*/
	endCli.sin_addr.s_addr= htonl(INADDR_ANY);
	endCli.sin_port        = htons(0);
	
	/* Cria socket para sender*/
	sd_cli = socket(PF_INET, SOCK_DGRAM, 0);
	if (sd_cli < 0) {
		fprintf(stderr, "Criacao do socket falhou!\n");
		exit(1); }
	/* liga socket a porta e ip */
	if (bind(sd_cli, (struct sockaddr *)&endCli, sizeof(endCli)) < 0) {
		fprintf(stderr,"Bind Falhou no Sender!\n");
		exit(1); }
	while(1)
	{
		time ( &rawtime );
		timeinfo = localtime ( &rawtime );
		memset(&bufout, 0x0, sizeof(bufout));
		sprintf(bufout, asctime(timeinfo));
		sendto(sd_cli,&bufout,strlen(bufout),0,(struct sockaddr *) &ladoServ, sizeof(ladoServ));
	}
}
